home *** CD-ROM | disk | FTP | other *** search
- Subject: v08i094: Repair damaged "cpio -c" archives
- Newsgroups: mod.sources
- Approved: mirror!rs
-
- Submitted by: rtech!daveb (Dave Brower)
- Mod.sources: Volume 8, Issue 94
- Archive-name: fixcpio
-
- [ I wrote the Makefile. --r$ ]
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line,
- # then unpack it by saving it in a file and typing "sh file".
- # If all goes well, you will see the message "End of shell archive."
- # Contents: README Makefile fixcpio.1 fixcpio.c
- PATH=/bin:/usr/bin:/usr/ucb; export PATH
- echo shar: extracting "'README'" '(339 characters)'
- if test -f 'README' ; then
- echo shar: will not over-write existing file "'README'"
- else
- sed 's/^X//' >README <<'@//E*O*F README//'
- XTue Jan 27 12:22:37 PST 1987
- X
- XThis is a program for fixing broken cpio -c archives. It is commonly
- Xused to recover a backup when disk 10 from a 30 disk archive has gotten
- Xtrashed.
- X
- XIt is often the "help" required by "Out of phase--get help."
- X
- XTo compile, either go:
- X
- X cc -O fixcpio.c -o fixcpio
- X
- Xor on System V say:
- X
- X make fixcpio
- X
- X-dB
- @//E*O*F README//
- if test 339 -ne "`wc -c <'README'`"; then
- echo shar: error transmitting "'README'" '(should have been 339 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'Makefile'" '(249 characters)'
- if test -f 'Makefile' ; then
- echo shar: will not over-write existing file "'Makefile'"
- else
- sed 's/^X//' >Makefile <<'@//E*O*F Makefile//'
- Xfixcpio: fixcpio.c
- X $(CC) $(CFLAGS) -o fixcpio fixcpio.c
- X
- X# Edit appropriately.
- XDESTDIR = /usr/local/bin
- XMANDIR = /usr/man/man1
- XMANPAGE = fixcpio.1
- Xinstall: fixcpio
- X cp fixcpio $(DESTDIR)
- X strip $(DESTDIR)/fixcpio
- X cp fixcpio.1 $(MANDIR)/$(MANPAGE)
- @//E*O*F Makefile//
- if test 249 -ne "`wc -c <'Makefile'`"; then
- echo shar: error transmitting "'Makefile'" '(should have been 249 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'fixcpio.1'" '(2243 characters)'
- if test -f 'fixcpio.1' ; then
- echo shar: will not over-write existing file "'fixcpio.1'"
- else
- sed 's/^X//' >fixcpio.1 <<'@//E*O*F fixcpio.1//'
- X.\" $Header: fixcpio.1,v 1.1 87/01/05 19:51:00 source Exp $
- X.TH FIXCPIO 1 "UNIX-PC" "Public Domain" "David Brower"
- X.ta 8n 16n 24n 32n 40n 48n 56n
- X.SH NAME
- Xfixcpio \- repair damaged cpio -c archives
- X.SH ORIGIN
- XDavid Brower, {gladys, sun, amdahl, mtxinu}!rtech!daveb
- X.SH SYNOPSIS
- X.B fixcpio
- X[ infile [ outfile ] ]
- X.SH DESCRIPTION
- X.I Fixcpio
- XReads the standard input (or the named \fIinfile\fP) and writes a cpio
- X-c archive to the standard output (or named \fIoutfile\fP).
- X.I Infile
- Xand
- X.I outfile
- Xmay be the dash character (`\-') to signify standard in or out.
- X.PP
- XThe input is presumed to be a \fIcpio -c\fP archive. While the input
- Xis copied to the output,
- X.I fixcpio
- Xchecks each archive member for sanity, and discards those that appear
- Xto be bad. The program writes the names of archive members copied on
- Xstderr, and says
- X.nf
- X
- X Skipping bad member ``filename''
- X
- X.fi
- Xfor each bad record. This eliminates the cheerful ``Out of phase--get help''
- Xmessage from cpio.
- X.PP
- XThe major use for
- X.I fixcpio
- Xis in recovering multiple floppy backups when one disk in the set goes
- Xbad. The process for the UNIX-PC is about as follows.
- X
- X.PP
- X1. Get images of the remaining floppies in files that are in alphabetical
- Xorder:
- X.nf
- X
- X # works with up to 99 disk backup sets.
- X #
- X # if, ibs, and count will depend on your machine and
- X # backup procedure.
- X disk=01
- X while :
- X do
- X echo "Interrupt to quit, return to read disk $disk \ec:"
- X read answer
- X dd if=/dev/rfp/021 ibs=1024 count=320 of=disk-$disk
- X dismount -f
- X disk=`awk "{ printf \e"%02d\en\e", $disk + 1 }" `
- X done
- X
- X.fi
- X.PP
- X2. Restore the contents of the disks with
- X.I fixcpio's
- Xhelp.
- X.nf
- X
- X cat disk-* | fixcpio | cpio -icdum
- X
- X.fi
- X.SH FILES
- X.br
- X/tmp Holds a temp file containing the archive member currently being examined.
- X.SH BUGS
- X.I Fixcpio
- Xdoes not understand binary cpio archives.
- X.PP
- XGetting disk images from the floppies depends on both the machine and
- X your backup procedures. You need to know how the floppies are
- X written before you start recovering, and this might be awkward if
- X you've lost your hard disk.
- X.PP
- XUsing a temp file is a kludge, needed because you can't seek around on
- Xinput from a pipe.
- X.PP
- XStatus messages should probably be toggled with a -v `verbose' flag.
- @//E*O*F fixcpio.1//
- if test 2243 -ne "`wc -c <'fixcpio.1'`"; then
- echo shar: error transmitting "'fixcpio.1'" '(should have been 2243 characters)'
- fi
- fi # end of overwriting check
- echo shar: extracting "'fixcpio.c'" '(9269 characters)'
- if test -f 'fixcpio.c' ; then
- echo shar: will not over-write existing file "'fixcpio.c'"
- else
- sed 's/^X//' >fixcpio.c <<'@//E*O*F fixcpio.c//'
- X
- X/*
- X** fixcpio.c -- fix troubled cpio archive by skipping trashed members.
- X**
- X** Dave Brower, 12/13/86
- X** {sun, amdahl, mtxinu}!rtech!daveb
- X**
- X** Usage: fixcpio [ infile [ outfile ] ]
- X**
- X** Writes a cpio -c archive to outfile (or stdout) from the infile (stdin).
- X** ("-" may be used as the stdin/stdout filename.)
- X**
- X** Skips over junk members. This is how to recover when you've lost
- X** floppy 9 of a 30 disk backup. Eliminates "Out of phase -- get help"
- X*/
- X
- X# include <stdio.h>
- X
- X/* size blocks to write */
- X
- X# define BLKSIZ 512
- X
- X/* Maximum reasonable pathname in a header record */
- X
- X# define MAXPATH 128
- X
- Xtypedef struct
- X{
- X /* these are ints for scanf's benefit. */
- X int h_magic,
- X h_dev,
- X h_ino,
- X h_mode,
- X h_uid,
- X h_gid,
- X h_nlink,
- X h_rdev;
- X long h_longtime;
- X int h_namesize;
- X long h_longfile;
- X} CHARHDR;
- X
- Xtypedef struct
- X{
- X CHARHDR h;
- X char h_name[ MAXPATH ];
- X} CHARREC;
- X
- XCHARREC CRec = { 0 }; /* Character header */
- Xchar Trailer[] = "TRAILER!!!"; /* Magic string */
- Xchar Tmpfile[] = "/tmp/fixcpioXXXXXX"; /* temp file template */
- Xint Debug; /* Debugging? */
- X
- Xvoid outerr(); /* error writing output file */
- Xvoid tmperr(); /* error writing temp file */
- Xvoid writeerr(); /* error writing file */
- Xint fprintf(); /* libc defined, -1 on error */
- X
- X/*
- X** main() -- fix a cpio archive with "Out of phase -- get help" problems.
- X*/
- Xmain(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X register int last; /* last char processed */
- X register int this; /* current chars */
- X register int nmagic; /* "07"s in magic "070707" seen */
- X
- X register FILE *ifp = stdin; /* input stream */
- X register FILE *ofp = stdout; /* output stream */
- X register FILE *tfp = NULL; /* temp file */
- X
- X int done = 0; /* all done flag */
- X long nbytes = 0; /* count of bytes written */
- X
- X char buf[ 512 ]; /* holds a trailer. */
- X
- X char *getenv(); /* libc defined */
- X FILE *efopen(); /* fopen, fatal on error */
- X FILE *getmember(); /* stash a member in a temp file */
- X long putmember(); /* write temp file */
- X
- X /* Set "secret" debugging flag */
- X Debug = getenv("FIXCPIO") != NULL;
- X
- X if( argc > 3 )
- X {
- X fprintf(stderr, "Usage: fixcpio [ infile [ outfile ] ]\n");
- X return( 1 );
- X }
- X
- X if( --argc > 0 && strcmp( *++argv, "-" ) )
- X ifp = efopen( *argv, "r" );
- X
- X if( --argc > 0 && strcmp( *++argv, "-" ) )
- X ofp = efopen( *argv, "w" );
- X
- X /*
- X ** Process chars of input. When you see a magic number, try
- X ** to accumulate the archive member on a temp file. Write out
- X ** good members as they are validated, skipping trouble makers.
- X */
- X for ( nmagic = last = this = 0 ; !done ; last = this )
- X {
- X switch( this = getc( ifp ) )
- X {
- X case '0':
- X
- X /* maybe a header, no special action */
- X break;
- X
- X case '7':
- X
- X /* Maintain count of special "07" pairs */
- X nmagic = last == '0' ? nmagic + 1 : 0;
- X
- X /* It's a magic number, try to process as a header */
- X if( nmagic == 3 )
- X {
- X nmagic = 0;
- X
- X /* stashed entry is good, write it */
- X if( tfp )
- X nbytes += putmember( tfp, ofp );
- X
- X /* stash this possible entry into tfp, get CRec */
- X tfp = getmember( ifp );
- X }
- X break;
- X
- X case EOF:
- X
- X done = 1;
- X /* Fall into... */
- X
- X default:
- X
- X /* Any existing entry is garbage... */
- X nmagic = 0;
- X if( tfp )
- X {
- X if( !strcmp( CRec.h_name, Trailer ) )
- X done = 1;
- X else
- X fprintf(stderr, "Skipping bad member \"%s\"\n",
- X CRec.h_name );
- X (void)fclose( tfp );
- X tfp = NULL;
- X }
- X break;
- X } /* switch */
- X } /* for */
- X
- X /* flush pending good member */
- X if( tfp )
- X {
- X nbytes += putmember( tfp, ofp );
- X tfp = NULL;
- X }
- X
- X /* Write a trailer -- remember to terminate the name string! */
- X (void)sprintf( buf, "070707%06o%06o%06o%06o%06o%06o%06o%011o%06o%011o%s",
- X 0, 0, 0, 0, 0, 0, 0, 0, sizeof(Trailer) + 1, 0, Trailer );
- X if( fprintf(ofp, "%s", buf) < 0 || putc( 0, ofp ) < 0 )
- X outerr();
- X nbytes += strlen( buf ) + 1;
- X
- X /* round output to an even block */
- X nbytes = BLKSIZ - (nbytes % BLKSIZ);
- X while( nbytes-- )
- X if( putc( 0, ofp ) < 0 )
- X outerr();
- X
- X if( fclose( ofp ) < 0 )
- X outerr();
- X return( 0 );
- X}
- X
- X/*
- X** getmember() -- save an archive member to a temp file
- X**
- X** When positioned after the magic number in a cpio file on ifp,
- X** copy the member to a temp file, and return it's fp. The temp file
- X** contains a complete member (including magic number) and is positioned
- X** for catting directly to the real output file.
- X**
- X** If there are problems getting the member, return NULL.
- X*/
- XFILE *
- Xgetmember( ifp )
- Xregister FILE *ifp;
- X{
- X register int c; /* character of the member name */
- X register int nr; /* number read or scanned */
- X register FILE *ofp; /* temp file */
- X long len; /* actual member length */
- X
- X char name[ sizeof(Tmpfile) + 1 ]; /* name of the temp file */
- X
- X /* number of chars to read for a -c header */
- X# define NCREAD ( (8 * 6) + (2 * 11) )
- X
- X char buf[ NCREAD + 1 ]; /* raw header */
- X
- X char *mktemp(); /* libc, make temp file name */
- X char *strcpy(); /* libc, copy string */
- X long ncat(); /* cat file to a length */
- X
- X if( NCREAD != ( nr = fread( buf, 1, NCREAD, ifp ) ) )
- X {
- X fprintf(stderr, "Couldn't read header: Wanted %d, got %d\n",
- X NCREAD, nr);
- X return (NULL);
- X }
- X
- X if( Debug )
- X {
- X fprintf(stderr,
- X "dev |ino |mode |uid |gid |nlink|rdev |longtime |nsize|longfile\n" );
- X fprintf(stderr, "%s\n", buf );
- X
- X }
- X
- X if( 10 != ( nr = sscanf( buf, "%6o%6o%6o%6o%6o%6o%6o%11o%6o%11o",
- X &CRec.h.h_dev, &CRec.h.h_ino, &CRec.h.h_mode,
- X &CRec.h.h_uid, &CRec.h.h_gid, &CRec.h.h_nlink,
- X &CRec.h.h_rdev, &CRec.h.h_longtime,
- X &CRec.h.h_namesize , &CRec.h.h_longfile ) ) )
- X {
- X fprintf(stderr, "Couldn't scan header: Wanted 10, got %d\n", nr);
- X return (NULL);
- X }
- X
- X if( Debug )
- X {
- X fprintf(stderr, "dev 0%o ino 0%o mode 0%o uid %d gid %d\n",
- X CRec.h.h_dev, CRec.h.h_ino, CRec.h.h_mode,
- X CRec.h.h_uid, CRec.h.h_gid );
- X fprintf(stderr,
- X "nlink %d rdev 0%o longtime 0%o namesize %d longfile 0%o\n",
- X CRec.h.h_nlink, CRec.h.h_rdev, CRec.h.h_longtime,
- X CRec.h.h_namesize, CRec.h.h_longfile );
- X }
- X
- X /* Ridiculous name size? probably trashed entry */
- X if( !CRec.h.h_namesize || CRec.h.h_namesize > sizeof( CRec.h_name ) )
- X {
- X fprintf(stderr, "Bad namesize %d\n", CRec.h.h_namesize );
- X return (NULL);
- X }
- X
- X /* Get the name */
- X nr = 0;
- X while( nr < CRec.h.h_namesize && ( c = getc( ifp ) ) != EOF )
- X CRec.h_name[ nr++ ] = c;
- X
- X if( c == EOF )
- X {
- X fprintf(stderr, "Unexpected EOF reading name in header\n");
- X return (NULL);
- X }
- X
- X if( Debug )
- X fprintf(stderr, "name \"%s\"\n", CRec.h_name );
- X
- X /* create a new temp file, and mark it for delete on close */
- X (void)strcpy( name, mktemp( Tmpfile ) );
- X ofp = efopen( name, "w+" );
- X (void)unlink( name );
- X
- X /* Write a header */
- X fprintf( ofp, "070707%06o%06o%06o%06o%06o%06o%06o%011o%06o%011o",
- X CRec.h.h_dev, CRec.h.h_ino, CRec.h.h_mode,
- X CRec.h.h_uid, CRec.h.h_gid, CRec.h.h_nlink,
- X CRec.h.h_rdev, CRec.h.h_longtime,
- X CRec.h.h_namesize, CRec.h.h_longfile ) ;
- X
- X for( nr = 0; nr < CRec.h.h_namesize ; )
- X putc( CRec.h_name[ nr++ ], ofp );
- X
- X /* now copy the file body */
- X if( CRec.h.h_longfile != (len = ncat( CRec.h.h_longfile, ifp, ofp ) ) )
- X {
- X fprintf(stderr, "Bad member length: Should be %ld, was %ld\n",
- X CRec.h.h_longfile, len );
- X (void)fclose( ofp );
- X return( NULL );
- X }
- X
- X if( fseek( ofp, 0L, 0 ) < 0L )
- X tmperr();
- X return( ofp );
- X
- X}
- X
- X/*
- X** putmember() -- Write member, close input and return bytes written
- X*/
- Xlong
- Xputmember( ifp, ofp )
- Xregister FILE * ifp;
- Xregister FILE * ofp;
- X{
- X register long n;
- X long cat();
- X
- X fprintf(stderr, "%s\n", CRec.h_name );
- X n = cat( ifp, ofp );
- X (void)fclose( ifp );
- X return ( n );
- X}
- X
- X
- X
- X/*
- X** cat() -- copy one stream to another, returning n bytes copied
- X*/
- Xlong
- Xcat( ifp, ofp )
- Xregister FILE *ifp;
- Xregister FILE *ofp;
- X{
- X register int c;
- X register int n;
- X
- X for( n = 0 ; ( c = getc( ifp ) ) != EOF ; n++ )
- X if( putc( c, ofp ) < 0 )
- X outerr();
- X
- X return ( n );
- X}
- X
- X/*
- X** ncat() -- copy up to n bytes from one stream to another, return actual
- X*/
- Xlong
- Xncat( in, ifp, ofp )
- Xregister long in;
- Xregister FILE *ifp;
- Xregister FILE *ofp;
- X{
- X register int c;
- X register long on;
- X
- X for( on = 0; in-- && ( c = getc( ifp ) ) != EOF ; on++ )
- X if( putc( c, ofp ) < 0 )
- X tmperr();
- X
- X return ( on );
- X}
- X
- X/*
- X** efopen() -- fopen() that fatals on error
- X*/
- XFILE *
- Xefopen( file, mode )
- Xchar *file;
- Xchar *mode;
- X{
- X FILE * fp;
- X
- X if( NULL == (fp = fopen( file, mode ) ) )
- X {
- X fprintf(stderr, "Can't open \"%s\" mode \"%s\"\n", file, mode );
- X perror("efopen");
- X exit( 1 );
- X }
- X return( fp );
- X}
- X
- X/*
- X** outerr() -- handle error writing output file
- X*/
- Xvoid
- Xouterr()
- X{
- X writeerr( "output" );
- X}
- X
- X/*
- X** tmperr() -- handle error writing temp file
- X*/
- Xvoid
- Xtmperr()
- X{
- X writeerr( "temp" );
- X}
- X
- X/*
- X** writeerr() -- handle write errors, gracelessly.
- X*/
- Xvoid
- Xwriteerr( what )
- Xchar *what;
- X{
- X fprintf(stderr, "\007Error writing %s file", what );
- X perror("");
- X
- X}
- X
- X/* end of fixcpio.c */
- @//E*O*F fixcpio.c//
- if test 9269 -ne "`wc -c <'fixcpio.c'`"; then
- echo shar: error transmitting "'fixcpio.c'" '(should have been 9269 characters)'
- fi
- fi # end of overwriting check
- echo shar: "End of shell archive."
- exit 0
-